﻿/*
   Copyright 2012 University of Southampton

   Licensed under the Apache License, Version 2.0 (the "License");
   you may not use this file except in compliance with the License.
   You may obtain a copy of the License at

       http://www.apache.org/licenses/LICENSE-2.0

   Unless required by applicable law or agreed to in writing, software
   distributed under the License is distributed on an "AS IS" BASIS,
   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   See the License for the specific language governing permissions and
   limitations under the License.
*/

using System;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Web.UI.WebControls.WebParts;
using System.Collections.Generic;
using uk.ac.soton.ses.DAL;
using System.Security.Principal;
using Microsoft.SharePoint;
using System.Linq;
using System.Web;

namespace uk.ac.soton.ses.UserControls
{
    public delegate void ExperimentSelectionChangedEventHandler(object sender, EventArgs e);

    public partial class ExperimentMultipleSelection : UserControl
    {
        //Requested experiment IDs
        public HashSet<int> RequestedExperimentIDs = null;

        //Loaded experiments (usually all experiments accessible to the user
        public Dictionary<int, Experiment> ExperimentsDictionary = null;

        public ExperimentSelectionChangedEventHandler ExperimentSelectionChanged;
        MaterialsMetadataContext dbcontext = null;
        private ExperimentQuickSearch _searchControl = null;
        private bool IsInitialised = false;

        protected override void OnInit(EventArgs e)
        {
            base.OnInit(e);
            try
            {
                //Load a database context
                this.dbcontext = HttpContext.Current.GetMaterialsDBContext();

                //Find the experiments quick search box, cast it, and store it in a field
                this._searchControl = this.ctl_ExperimentQuickSearch as ExperimentQuickSearch;

                //Set up events
                this._searchControl.ExperimentSelected += new ExperimentSelectedEventHandler(this.QuickSearchControl_ExperimentSelected);
                this.lst_Datasets.SelectedIndexChanged += new EventHandler(lst_Datasets_SelectedIndexChanged);

                //Load all experiments the user has access to
                this.LoadExperiments();

                //Find out which experiments user has requested and load them
                this.ProcessExperimentQueryString();

                //Let OnLoad do its stuff
                this.IsInitialised = true;
            }
            catch (Exception)
            {
                HDCSharedWebFunctions.AddErrorLabel("Could not load data", this.PlaceHolder_Messages);
                this.IsInitialised = false;
            }
        }

        protected override void OnLoad(EventArgs e)
        {
            base.OnLoad(e);

            if(this.IsInitialised && !Page.IsPostBack)
            {
                this.PopulateDatasetList();
            }
        }

        private void LoadExperiments()
        {
            //Lookup current user
            WindowsIdentity identity = Context.User.Identity as WindowsIdentity;

            //Get the user's experiments
            IEnumerable<Experiment> usersExperiments = null;

            //A WMI Query might be required which needs elevated priveleges
            SPSecurity.RunWithElevatedPrivileges(delegate()
            {
                usersExperiments = this.dbcontext.GetExperimentsForUser(identity.User, HDCExperimentAccessLevels.ReadOnly);
            });

            this.ExperimentsDictionary = (usersExperiments.ToDictionary(exp => exp.ID));
        }


        private void ProcessExperimentQueryString()
        {
            try
            {
                //Parse query string
                string[] experimentIDStrings = Page.Request.QueryString.GetValues("ExperimentID") ?? new string[0];
                IEnumerable<int> experimentIDs = experimentIDStrings.Select(id => int.Parse(id)).Distinct();
                this.RequestedExperimentIDs = (new HashSet<int>(experimentIDs));
            }
            catch (Exception ex)
            {
                if (ex is FormatException || ex is OverflowException || ex is ArgumentNullException)
                {
                    HDCSharedWebFunctions.AddErrorLabel("Could not parse experiment ID", this.PlaceHolder_Messages);
                }
                throw;
            }
        }

        private void lst_Datasets_SelectedIndexChanged(object sender, EventArgs e)
        {
            List<int> selectedExperiments = new List<int>();
            foreach (ListItem li in this.lst_Datasets.Items)
            {
                if (li.Selected)
                {
                    try
                    {
                        int id = int.Parse(li.Value);
                        selectedExperiments.Add(id);
                    }
                    catch (Exception ex)
                    {
                        if (ex is FormatException || ex is OverflowException || ex is ArgumentNullException)
                        {
                            HDCSharedWebFunctions.AddErrorLabel("Experiment ID not correct format", this.PlaceHolder_Messages);
                            return;
                        }
                        else
                        {
                            throw;
                        }
                    }
                }
            }

            this.RequestedExperimentIDs = new HashSet<int>(selectedExperiments.Distinct());

            this.ExperimentSelectionChanged(this, new EventArgs());
        }


        private void QuickSearchControl_ExperimentSelected(object sender, ExperimentSelectedEventArgs e)
        {
            this.RequestedExperimentIDs.Add(e.SelectedExperimentID);

            this.ExperimentSelectionChanged(this, new EventArgs());
        }


        private void PopulateDatasetList()
        {
            //Clear existing items
            this.lst_Datasets.Items.Clear();

            //Create ListItems for list
            List<ListItem> listItems = new List<ListItem>();

            foreach (int expID in this.RequestedExperimentIDs)
            {
                Experiment exp;
                if (this.ExperimentsDictionary.TryGetValue(expID, out exp))
                {
                    ListItem newListItem = new ListItem(exp.GetNameAndID(), exp.ID.ToString());
                    newListItem.Selected = this.RequestedExperimentIDs.Contains(exp.ID);
                    listItems.Add(newListItem);
                }
            }

            //Populate list
            this.lst_Datasets.Items.AddRange(
                //Sort it
                listItems.OrderBy(li => li.Text)
                //Convert it to an array
                .ToArray()
                );
        }
    }
}
